﻿/*global Ext.ux */
/**
 * @class Ext.ux.form.BizComboBox
 * @extends Ext.form.ComboBox
 *
 * Simple list of values Combo
 *
 * @author    Zheng Kejun
 * @copyright (c) 2013, by Zheng Kejun
 * @version   0.1
 * @date      <ul>
 * <li>2013-07-31</li>
 * <li>2013-08-01</li>
 * </ul>
 * @revision  $Id: Ext.ux.form.BizComboBox.js 733 2009-06-26 07:29:07Z Zheng kejun $
 *
 * @license Ext.ux.form.BizComboBox.js is licensed under the terms of the Open Source
 * LGPL 3.0 license. Commercial use is permitted to the extent that the 
 * code/component(s) do NOT become part of another Open Source or Commercially
 * licensed development library or toolkit without explicit permission.
 * 
 * <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html"
 * target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p>
 *
 * @forum     32692
 * @demo      http://www.waylink.net
 * @download  
 * <ul>
 * <li><a href="http://www.waylink.net/bizcombo.zip">bizcombo.zip</a></li>
 * </ul>
 *
 * @donate
 * <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
 * <input type="hidden" name="cmd" value="_s-xclick">
 * <input type="hidden" name="hosted_button_id" value="3430419">
 * <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" 
 * border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
 * <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
 * </form>
 */

// create namespace
Ext.ns('Ext.ux.form');

/**
 * Creates new BizComboBox
 * @constructor
 * @param {Object} config A config object
 */
Ext.ux.form.BizComboBox = Ext.extend(Ext.form.ComboBox, {

    // configuration options
    /**
     * @cfg {Boolean} multiSelect
     * True to allow selection of more than one item at a time, false to allow selection of only a single item
     * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).
     */
	multiSelect:false
    /**
     * @cfg {Boolean} singleSelect
     * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).
     * Note that if {@link #multiSelect} = true, this value will be ignored.
     */
	,singleSelect:false
    /**
     * @cfg {Boolean} simpleSelect
     * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,
     * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).
     */
	,simpleSelect:false
	
	/**
	 * @cfg {String} separator Separator to use between values and texts (defaults to "," (comma))
	 */
    ,separator:','
    	
	/**
	 * @cfg {String} valueSeparator Separator to use between values and texts (defaults to "," (comma))
	 */
    ,valueSeparator:','
   	
	/**
	 * @cfg {String} displaySeparator Separator to use between display labels and texts (defaults to "," (comma))
	 */
    ,displaySeparator:','

	/**
	 * @cfg {String/Array} tpl Template for items. 
	 * Change it only if you know what you are doing.
	 */
	,constructor:function(config) {
		config = config || {};
		config.listeners = config.listeners || {};
		Ext.applyIf( config.listeners, {scope:this,blur:this.onRealBlur} );
		Ext.ux.form.BizComboBox.superclass.constructor.call(this, config);
	}
    ,initComponent:function() {
        // call parent
        Ext.ux.form.BizComboBox.superclass.initComponent.apply(this, arguments);
		// remove selection from input field
		this.onLoad = this.onLoad.createSequence(function() {
			if(this.el) {
				var v = this.el.dom.value;
				this.el.dom.value = '';
				this.el.dom.value = v;
			}
		});
 
    }

	/**
	 * Disables default tab key bahavior
	 * @private
	 */
	,initEvents:function() {
		Ext.ux.form.BizComboBox.superclass.initEvents.apply(this, arguments);
		// disable default tab handling - does no good
		this.keyNav.tab = false;

	}
	/**
	 * blur event handler - runs only when real blur event is fired
	 * @private
	 */
	,onRealBlur:function() {
		this.view.clearSelections(true);
		//this.list.hide();
	}
	/**
	 * @return {String} separator separated list of selected values by Field
	 * @private
	 */
	,getSelectedValuesByField:function(field,separator) {
		var c = [];
		//var recs = this.view.selected.elements;
		var recs = this.view.getSelectedRecords();
		for(var i=0;i<recs.length;i++){
			if(recs[i]){
				c.push(recs[i].get(field));
			}
		}
		var v = c.join(separator);
		return v;
	} 

	/**
	 * @return {String} separator separated list of selected valueFields
	 * @private
	 */
	,getValues:function() {
		var field = this.valueField;
		var separator = this.valueSeparator||this.separator;
		return this.getSelectedValuesByField(field,separator);
	} 

	/**
	 * Combo's onSelect override
	 * @private
	 * @param {Ext.data.Record} record record that has been selected in the list
	 * @param {Number} index index of selected (clicked) record
	 */
	,onSelect:function(record, index) {
        if(this.fireEvent('beforeselect', this, record, index) !== false){
			// display full list
			if(this.store.isFiltered()) {
				this.doQuery(this.allQuery);
			}
			this.fillValues();
            this.fireEvent('select', this, record, index);
        }
	} // eo function onSelect
    

	/**
	 * Sets the value of the BizComboBox. The passed value can by a falsie (null, false, empty string), in
	 * which case the combo value is cleared or separator separated string of values, e.g. '3,5,6'.
	 * @param {Mixed} v value
	 */
	,setValue:function(v) {
		if(  Ext.isEmpty(v) ){
			this.clearValue();
			if( this.autoSelect && (this.store.getCount()>0) ){
				this.select(0);
				this.fillValues();
			}
		}else {
			if( this.valueField && (this.store.getCount()>0)) {
				this.store.clearFilter();
				this.selectByValue(v);
				this.fillValues(v);
			}else{
				this.fillValues(v);				
			}
			if( this.el ) {
				this.el.removeClass(this.emptyClass);
			}
		}
	} 
	   // private
    ,assertValue : function(){
        var val = this.getRawValue(), recs=[];

        if(this.valueField && Ext.isDefined(this.value)){
            recs = this.findRecords(this.valueField, this.value);
        }
        if( recs.length==0){
            recs = this.findRecords(this.displayField, val);
        }
        if( recs.length==0 && this.forceSelection ){
            if(val.length > 0 && val != this.emptyText){
                this.el.dom.value = Ext.value(this.lastSelectionText, '');
                this.applyEmptyText();
            }else{
                this.clearValue();
            }
        }else{
            if(recs.length>0 && this.valueField){
                // onSelect may have already set the value and by doing so
                // set the display field properly.  Let's not wipe out the
                // valueField here by just sending the displayField.
                if (this.value == val){
                    return;
                }
                var c = [];
        		for(var i=0;i<recs.length;i++){
        			if(recs[i]){
        				c.push(recs[i].get(this.valueField));
        			}
        		}
        		val = c.join(this.valueSeparator||this.separator);
            }
            this.setValue(val);
        }
    }

    // private
    ,findRecords : function(fld, value){
    	if(Ext.isEmpty(value)){return false;}
        var records=[];
		var recs =  this.store.getRange();//this.store.snapshot||this.store.data;
		for(var i=0;i<recs.length;i++){
			if(this.validRecord(value,recs[i],fld)){ 
				records.push(recs[i]); 
			};
		}
        return records;
    }

	/**
    * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
    * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
    * @param {String} value The data value of the item to select
    * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
    * selected item if it is not currently in view (defaults to true)
    * @return {Boolean} True if the value matched an item in the list, else false
    */
   ,selectByValue : function(value, scrollIntoView){
      	if(Ext.isEmpty(value)){return false;}    
		var exist = false;
		var recs =  this.store.getRange();//this.store.snapshot||this.store.data;
		for(var i=0;i<recs.length;i++){
			if(this.validRecord(value,recs[i],this.valueField)){ 
				this.select(i); 
				exist=true;
			};
		}
      	return exist;
   }  
   
   ,validRecord:function(value,rec,fld){
		var spChar = Ext.escapeRe(this.valueSeparator||this.separator);
		var regStr = '(^|'+spChar+')' + Ext.escapeRe(rec.get(fld)) + '('+spChar+'|$)';
		//alert(value+" match(regStr) "+regStr+":"+(value.match(regStr)?true:false));
		return value.match(regStr)?true:false;
   }
   //override:super is auto selct;
   ,onViewOver:function(){
	   
   }

	//dataview select
   ,select : function(index, scrollIntoView){
	   //alert(this.name+" select:"+index);
       this.selectedIndex = index;
       this.view.select(index,this.multiSelect,true);
       if(scrollIntoView !== false){
           var el = this.view.getNode(index);
           if(el){
               this.innerList.scrollChildIntoView(el, false);
           }
       }
   }

	/**
	 * Selects all items
	 */
	,selectAll:function() {
        //display full list
        this.doQuery(this.allQuery);
        this.store.each(function(rec){
        	this.view.select(rec,true,true);
        }, this);
        this.fillValues();
    } // eo full selectAll

	/**
	 * Deselects all items. Synonym for clearValue
	 */
    ,deselectAll:function() {
		this.clearValue();
    } 
    
    //private;
    ,fillValues:function(defaultValues){
    	var valueTexts = this.getValues();
 		this.value = valueTexts?valueTexts:defaultValues;
		if( this.hiddenField ) {
			this.hiddenField.value = this.value;
		}
		var field = this.displayField;
		var separator = this.displaySeparator||this.separator;
		var labelTexts = this.getSelectedValuesByField(field,separator);
		this.setRawValue(labelTexts?labelTexts:defaultValues);    	
       // Ext.form.ComboBox.superclass.setValue.call(this, this.value);
    }
    
    // private
    ,initList : function(){
     	Ext.ux.form.BizComboBox.superclass.initList.call(this);
    	this.view.multiSelect =this.multiSelect;
       	this.view.singleSelect=this.singleSelect;
       	this.view.simpleSelect=this.simpleSelect;
      }

});

// register xtype
Ext.reg('bizcombo', Ext.ux.form.BizComboBox); 
